package com.laker.admin.module.inv.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.laker.admin.config.LakerConfig;
import com.laker.admin.module.inv.entity.InvMessage;
import com.laker.admin.module.inv.entity.InvTradein;
import com.laker.admin.module.inv.entity.InvTradeout;
import com.laker.admin.module.inv.mapper.InvMessageMapper;
import com.laker.admin.module.inv.mapper.InvTradeinMapper;
import com.laker.admin.module.inv.mapper.InvTradeoutMapper;
import com.laker.admin.module.inv.service.IInvMessageService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.laker.admin.module.inv.vo.InvMessageGroupVO;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.*;
import org.imgscalr.Scalr;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author laker
 * @since 2024-03-21
 */
@Service
public class InvMessageServiceImpl extends ServiceImpl<InvMessageMapper, InvMessage> implements IInvMessageService {

    @Resource
    private InvMessageMapper invMessageMapper;

    @Resource
    private InvTradeinMapper invTradeinMapper;

    @Resource
    private InvTradeoutMapper invTradeoutMapper;

    @Autowired
    LakerConfig lakerConfig;

    @Override
    public String getAll(Wrapper queryWrapper) {
        // 1、设置参数
        List<InvMessage> list = invMessageMapper.selectList(queryWrapper);
        List<InvMessageGroupVO> list2 = invMessageMapper.selectGroupbyCommList(queryWrapper);

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
        SimpleDateFormat sdfTime = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
        Calendar ca = Calendar.getInstance();
        String saveTitle = "商品库存";
        DecimalFormat df = new DecimalFormat("#,##0");
        int allRow = 5;

        // 2、创建一个临时的 excel 文件，配置单元格属性，数值格式。
        FileOutputStream os = null;
        String filePath = new File(lakerConfig.getOssFile().getPath()).getAbsolutePath() + File.separator;
        String resultFileName = "";
        try {
            // 2.1、创建对象
            XSSFWorkbook wb = new XSSFWorkbook();
            XSSFSheet sheet = wb.createSheet(saveTitle);

            // 2.2、初始化样式
            Map<String, XSSFCellStyle> styles = this.createStyles(wb);

            // 2.3、设置表头
            XSSFRow row01 = sheet.createRow(0);
            XSSFRow row02 = sheet.createRow(1);
            XSSFRow row03 = sheet.createRow(2);
            XSSFRow row04 = sheet.createRow(3);
            XSSFRow row05 = sheet.createRow(4);

            // 2.3.1、合并单元格，表头居中，设置列宽
            sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 6));
            sheet.addMergedRegion(new CellRangeAddress(1, 1, 0, 6));
            sheet.addMergedRegion(new CellRangeAddress(2, 2, 1, 2));
            sheet.addMergedRegion(new CellRangeAddress(2, 2, 4, 6));
            sheet.addMergedRegion(new CellRangeAddress(3, 3, 0, 6));
            row01.createCell(0).setCellValue(saveTitle);
            row02.createCell(0).setCellValue("");
            row03.createCell(0).setCellValue("时间：");
            row03.createCell(1).setCellValue(sdf.format(ca.getTime()));
            row03.createCell(3).setCellValue("单位：");
            row04.createCell(0).setCellValue("");

            row01.getCell(0).setCellStyle(styles.get("aligntitle"));
            row03.getCell(0).setCellStyle(styles.get("others"));
            row03.getCell(1).setCellStyle(styles.get("left"));
            row03.getCell(3).setCellStyle(styles.get("others"));

            // 2.4 设置标题行
            row05.createCell(0).setCellValue("序号");
            row05.createCell(1).setCellValue("库存编号");
            row05.createCell(2).setCellValue("商品类别");
            row05.createCell(3).setCellValue("商品名称");
            row05.createCell(4).setCellValue("商品规格");
            row05.createCell(5).setCellValue("商品数量");
            row05.createCell(6).setCellValue("商品图片");
            row05.getCell(0).setCellStyle(styles.get("aligncenterbold"));
            row05.getCell(1).setCellStyle(styles.get("aligncenterbold"));
            row05.getCell(2).setCellStyle(styles.get("aligncenterbold"));
            row05.getCell(3).setCellStyle(styles.get("aligncenterbold"));
            row05.getCell(4).setCellStyle(styles.get("aligncenterbold"));
            row05.getCell(5).setCellStyle(styles.get("aligncenterbold"));
            row05.getCell(6).setCellStyle(styles.get("aligncenterbold"));

            sheet.setColumnWidth(0, 2000);
            sheet.setColumnWidth(1, 3200);
            sheet.setColumnWidth(2, 3600);
            sheet.setColumnWidth(3, 4800);
            sheet.setColumnWidth(4, 2800);
            sheet.setColumnWidth(5, 2800);
            sheet.setColumnWidth(6, 3200);

            // 2.5 写入数据
            if (list != null && list.size() > 0) {
                allRow += list.size();
                for (int i = 0; i < list.size(); i++) {
                    InvMessage message = list.get(i);
                    XSSFRow row06 = sheet.createRow(i + 5);

                    row06.createCell(0).setCellValue(i + 1);
                    row06.createCell(1).setCellValue(message.getInvId());
                    row06.createCell(2).setCellValue(message.getCommTypeName());
                    row06.createCell(3).setCellValue(message.getCommName());
                    row06.createCell(4).setCellValue(message.getCommSpecsName());
                    row06.createCell(5).setCellValue(df.format(message.getInvSum()));
                    row06.createCell(6).setCellValue("");

                    row06.getCell(0).setCellStyle(styles.get("aligncenter"));
                    row06.getCell(1).setCellStyle(styles.get("aligncenter"));
                    row06.getCell(2).setCellStyle(styles.get("aligncenter"));
                    row06.getCell(3).setCellStyle(styles.get("alignleft"));
                    row06.getCell(4).setCellStyle(styles.get("aligncenter"));
                    row06.getCell(5).setCellStyle(styles.get("alignright"));
                    row06.getCell(6).setCellStyle(styles.get("aligncenter"));

//                    CTRow ctRow = row06.getCTRow();
//                    ctRow.setCustomHeight(true);
                }

                // 插入图片
                int mergedRow = 0;
                for (int j = 0; j < list2.size(); j++) {
                    InvMessageGroupVO vo = list2.get(j);
                    String commPicName = vo.getCommPicName();
                    Integer fileNum = vo.getFileNum();

                    if (fileNum > 1) {
                        sheet.addMergedRegion(new CellRangeAddress(j + 5 + mergedRow, j + 5 + mergedRow + fileNum - 1, 6, 6));
                    }

                    if (StringUtils.isNotEmpty(commPicName)) {
                        setIntoSheet(wb, sheet, j + 5 + mergedRow, 6, fileNum, filePath + commPicName);
                    }

                    mergedRow += (fileNum - 1);
                }
            }

            // 2.6 设置页脚
            XSSFRow rowBottom = sheet.createRow(allRow + 1);
            rowBottom.createCell(1).setCellValue("经办人：");
            rowBottom.createCell(4).setCellValue("经办日期：");
            rowBottom.getCell(1).setCellStyle(styles.get("others"));
            rowBottom.getCell(4).setCellStyle(styles.get("others"));

            // 2.7、设置合计sheet可见
            wb.setFirstVisibleTab(0);

            // 2.8、将文件存到指定位置
            String fileName = saveTitle + "_" + sdfTime.format(ca.getTime()) + ".xlsx";
            try {
                // 创建文件
                File resultFile = new File(filePath, fileName);
                resultFile.createNewFile();
                os = new FileOutputStream(resultFile);
                wb.write(os);
                os.flush();
            } catch (Exception e) {
                e.printStackTrace();
            }

            resultFileName = lakerConfig.getOssFile().getDomain() + File.separator + lakerConfig.getOssFile().getPath() + File.separator + fileName;
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            try {
                os.flush();
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return resultFileName;
    }

    @Override
    public boolean tradein(InvMessage entity) {
        boolean result = invMessageMapper.tradeinById(entity) > 0 ? true : false;
        if (result) {
            InvTradein invTradein = new InvTradein();
            invTradein.setInvId(entity.getInvId());
            invTradein.setInvTradeinProductId(entity.getCommId());
            invTradein.setInvCommSpaceId(entity.getCommSpecsId());
            invTradein.setInvTradeinProdSum(entity.getTransSum());
            invTradein.setInvTradeinModifySum(entity.getTransSum());
            invTradein.setInvTradeinReceive(entity.getInvTradeinReceive());
            invTradein.setInvTradeinTime(entity.getTransDate());
            invTradein.setInvTradeinRemark(entity.getTransRemark());

            result = invTradeinMapper.insert(invTradein) > 0 ? true : false;
        }

        return result;
    }

    @Override
    public boolean tradeout(InvMessage entity) {
        boolean result = invMessageMapper.tradeoutById(entity) > 0 ? true : false;
        if (result) {
            InvTradeout invTradeout = new InvTradeout();
            invTradeout.setInvId(entity.getInvId());
            invTradeout.setInvTradeoutProductId(entity.getCommId());
            invTradeout.setInvTradeoutCommSpaceId(entity.getCommSpecsId());
            invTradeout.setInvTradeoutProdSum(entity.getTransSum());
            invTradeout.setInvTradeoutModifySum(entity.getTransSum());
            invTradeout.setInvTradeoutReceive(entity.getInvTradeoutReceive());
            invTradeout.setInvTradeioutTime(entity.getTransDate());
            invTradeout.setInvTradeoutRemark(entity.getTransRemark());
            result = invTradeoutMapper.insert(invTradeout) > 0 ? true : false;
        }

        return result;
    }

    @Override
    public boolean deleteByCommid(Long id) {
        QueryWrapper<InvMessage> wrapper = new QueryWrapper<>();
        wrapper.eq("comm_id", id);
        return invMessageMapper.delete(wrapper) != 0;
    }

    @Override
    public int invAllCount() {
        return invMessageMapper.invAllCount();
    }

    @Override
    public int selectCountByCommId(Long id) {
        return invMessageMapper.selectCountByCommId(id);
    }

    @Override
    public int tradeinAllCount() {
        return invTradeinMapper.tradeinAllCount();
    }

    @Override
    public int tradeoutAllCount() {
        return invTradeoutMapper.tradeoutAllCount();
    }

    @Override
    public int tradeoutPersonCount() {
        return invTradeoutMapper.tradeoutPersonCount();
    }

    private Map<String, XSSFCellStyle> createStyles(XSSFWorkbook wb) {
        // 1、定义参数
        Map<String, XSSFCellStyle> styles = new HashMap<String, XSSFCellStyle>();

        XSSFFont font1 = wb.createFont();
        font1.setFontName("宋体");
        font1.setBold(true);
        font1.setFontHeightInPoints((short) 22);

        XSSFFont font2 = wb.createFont();
        font2.setFontName("宋体");
        font2.setBold(true);
        font2.setFontHeightInPoints((short) 12);

        XSSFFont font3 = wb.createFont();
        font3.setFontName("宋体");
        font3.setFontHeightInPoints((short) 12);

        XSSFCellStyle style1 = wb.createCellStyle();
        style1.setAlignment(HorizontalAlignment.CENTER);
        style1.setFont(font1);
        styles.put("aligntitle", style1);

        XSSFCellStyle style2 = wb.createCellStyle();
        style2.setAlignment(HorizontalAlignment.RIGHT);
        style2.setFont(font3);
        style2.setBorderBottom(BorderStyle.THIN);
        style2.setBorderLeft(BorderStyle.THIN);
        style2.setBorderRight(BorderStyle.THIN);
        style2.setBorderTop(BorderStyle.THIN);
        styles.put("alignright", style2);

        XSSFCellStyle style3 = wb.createCellStyle();
        style3.setAlignment(HorizontalAlignment.RIGHT);
        style3.setFont(font2);
        style3.setBorderBottom(BorderStyle.THIN);
        style3.setBorderLeft(BorderStyle.THIN);
        style3.setBorderRight(BorderStyle.THIN);
        style3.setBorderTop(BorderStyle.THIN);
        styles.put("alignrightbold", style3);

        XSSFCellStyle style4 = wb.createCellStyle();
        style4.setAlignment(HorizontalAlignment.CENTER);
        style4.setFont(font3);
        style4.setBorderBottom(BorderStyle.THIN);
        style4.setBorderLeft(BorderStyle.THIN);
        style4.setBorderRight(BorderStyle.THIN);
        style4.setBorderTop(BorderStyle.THIN);
        styles.put("aligncenter", style4);

        XSSFCellStyle style5 = wb.createCellStyle();
        style5.setAlignment(HorizontalAlignment.CENTER);
        style5.setVerticalAlignment(VerticalAlignment.CENTER);
        style5.setFont(font2);
        //设置自动换行
        style5.setWrapText(true);
        style5.setBorderBottom(BorderStyle.THIN);
        style5.setBorderLeft(BorderStyle.THIN);
        style5.setBorderRight(BorderStyle.THIN);
        style5.setBorderTop(BorderStyle.THIN);
        styles.put("aligncenterbold", style5);

        XSSFCellStyle style6 = wb.createCellStyle();
        style6.setAlignment(HorizontalAlignment.RIGHT);
        style6.setFont(font3);
        styles.put("others", style6);

        XSSFCellStyle style8 = wb.createCellStyle();
        style8.setAlignment(HorizontalAlignment.LEFT);
        style8.setFont(font3);
        styles.put("left", style8);

        XSSFCellStyle style7 = wb.createCellStyle();
        style7.setAlignment(HorizontalAlignment.LEFT);
        style7.setFont(font3);
        style7.setBorderBottom(BorderStyle.THIN);
        style7.setBorderLeft(BorderStyle.THIN);
        style7.setBorderRight(BorderStyle.THIN);
        style7.setBorderTop(BorderStyle.THIN);
        styles.put("alignleft", style7);

        return styles;
    }

    /**
     * 将图片bytes添加到Excel中
     */
    private void setIntoSheet(XSSFWorkbook wb, Sheet sheet, int rowNum, int colNum, int fileNum, String imageUrl) {
        ScaledImageDataDTO scaledImageDataDTO = scaleImage(imageUrl, fileNum);
        byte[] imageBytes = scaledImageDataDTO.getScaledImage();
        int imageHeight = scaledImageDataDTO.getHeight();

        int pictureIdx = wb.addPicture(imageBytes, Workbook.PICTURE_TYPE_PNG);
        CreationHelper helper = wb.getCreationHelper();
        Drawing drawing = sheet.createDrawingPatriarch();
        ClientAnchor anchor = helper.createClientAnchor();

        // 设置图片位置
        anchor.setRow1(rowNum);
        anchor.setCol1(colNum);

//        anchor.setCol2(sheet.getColumnWidth(colNum)); // 结束列，这里简单使用第一列的宽度，实际应用中可能需要动态计算或使用sheet的宽度信息
//        anchor.setRow2((int) sheet.getRow(rowNum).getHeightInPoints()); // 结束行，使用第一行的高度信息
//        anchor.setAnchorType(ClientAnchor.AnchorType.DONT_MOVE_AND_RESIZE); // 设置为不移动不改变大小模式

        // 设置行高度以匹配图片高度
        if (fileNum == 1) {
            Row row = sheet.getRow(rowNum);
            row.setHeightInPoints((float) 80);
        } else if (fileNum == 2) {
            Row row = sheet.getRow(rowNum);
            row.setHeightInPoints((float) 40);
            Row row1 = sheet.getRow(rowNum + 1);
            row1.setHeightInPoints((float) 40);
        } else {
            for (int i = 0; i < fileNum; i++) {
                Row row = sheet.getRow(rowNum + i);
                row.setHeightInPoints((float) 27);
            }
        }

        XSSFCellStyle style = wb.createCellStyle();
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setBorderBottom(BorderStyle.THIN);
        style.setBorderLeft(BorderStyle.THIN);
        style.setBorderRight(BorderStyle.THIN);
        style.setBorderTop(BorderStyle.THIN);
        Row row = sheet.getRow(rowNum);
        row.getCell(colNum).setCellStyle(style);

        // 插入图片到指定位置
        Picture picture = drawing.createPicture(anchor, pictureIdx);
        picture.resize();
    }

    /**
     * 缩放图片 转bytes
     */
    private ScaledImageDataDTO scaleImage(String imageUrl, int fileNum) {
        InputStream inputStream = null;
        int desiredHeight = 0;
        BufferedImage scaledImage = null;
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        try {
            inputStream = new FileInputStream(new File(imageUrl));
            BufferedImage targetImage = ImageIO.read(inputStream);

            // 图片宽度 固定
            int desiredWidth = 89;
            // 图片高度 根据跨行进行分析
            if (fileNum <= 3) {
                desiredHeight = 102;
            } else {
                desiredHeight = (fileNum * (102/3));
            }

            double aspectRatio = (double) targetImage.getHeight() / targetImage.getWidth();
            desiredHeight = (int) (desiredWidth * aspectRatio);

            scaledImage = Scalr.resize(targetImage, Scalr.Method.QUALITY, desiredWidth, desiredHeight);

            // 转byte
            ImageIO.write(scaledImage, "png", stream);
        } catch (Exception e) {
            return new ScaledImageDataDTO(desiredHeight, new byte[0]);
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return new ScaledImageDataDTO(desiredHeight, stream.toByteArray());
    }

    private class ScaledImageDataDTO {
        private int height;
        private byte [] scaledImage;

        public ScaledImageDataDTO (int height, byte [] scaledImage) {
            this.height = height;
            this.scaledImage = scaledImage;
        }

        public int getHeight() {
            return height;
        }

        public void setHeight(int height) {
            this.height = height;
        }

        public byte[] getScaledImage() {
            return scaledImage;
        }

        public void setScaledImage(byte[] scaledImage) {
            this.scaledImage = scaledImage;
        }

        @Override
        public String toString() {
            return "ScaledImageDataDTO{" +
                    "height=" + height +
                    '}';
        }
    }
}
